﻿#pragma once

#include <xy/utils/singleton.h>

#include <functional>
#include <map>
#include <memory>
#include <string>
#include <vector>

namespace xy
{

namespace utils
{

// 反射基类，反射类需继承此类
class reflective;

namespace details
{

// 构造指针
using creator = std::unique_ptr<reflective> (*)();

class reflection_field
{
  public:
    reflection_field(reflection_field &&) = delete;

    /**
     * @brief 默认构造
     *
     */
    reflection_field() = default;

    /**
     * @brief 标准构造
     *
     * @param[in] name
     * @param[in] type
     * @param[in] offset
     */
    reflection_field(const std::string &name, const std::string &type, std::size_t offset)
        : m_name(name), m_type(type), m_offset(offset)
    {
    }

    /**
     * @brief 字段名
     *
     * @return const std::string&
     */
    const std::string &name() const noexcept
    {
        return m_name;
    }

    /**
     * @brief 字段类型
     *
     * @return const std::string&
     */
    const std::string &type() const noexcept
    {
        return m_type;
    }

    /**
     * @brief 偏移量
     *
     * @return std::size_t
     */
    std::size_t offset() const noexcept
    {
        return m_offset;
    }

  private:
    std::string m_name;
    std::string m_type;
    std::size_t m_offset;
};

class reflection_method
{
  public:
    reflection_method(reflection_method &&) = delete;

    /**
     * @brief 默认构造
     *
     */
    reflection_method() = default;

    /**
     * @brief 标准构造
     *
     * @param[in] name
     * @param[in] method
     */
    reflection_method(const std::string &name, uintptr_t method) : m_name(name), m_method(method)
    {
    }

    /**
     * @brief 方法名
     *
     * @return const std::string&
     */
    const std::string &name() const noexcept
    {
        return m_name;
    }

    /**
     * @brief 方法指针
     *
     * @return uintptr_t
     */
    uintptr_t method() const noexcept
    {
        return m_method;
    }

  private:
    std::string m_name;
    uintptr_t m_method;
};

class reflection_factory
{
    friend class singleton<reflection_factory>;

  private:
    reflection_factory() = default;
    ~reflection_factory() = default;
    reflection_factory(reflection_factory &&) = delete;

  public:
    /**
     * @brief 注册类
     *
     * @param[in] className
     * @param[in] creator
     */
    void register_class(const std::string &className, creator creator)
    {
        m_creators[className] = creator;
    }

    /**
     * @brief 创建类
     *
     * @param[in] className
     * @return std::unique_ptr<reflective>
     */
    std::unique_ptr<reflective> create_class(const std::string &className)
    {
        auto it = m_creators.find(className);
        if (it == m_creators.end())
            return nullptr;

        // 调用 creator 指针指向的函数，返回创建的对象指针
        return it->second();
    }

    /**
     * @brief 注册类字段
     *
     * @param[in] className
     * @param[in] fieldName
     * @param[in] fieldType
     * @param[in] offset
     */
    void register_field(const std::string &className, const std::string &fieldName, const std::string &fieldType,
                        std::size_t offset)
    {
        m_fields[className].emplace_back(std::make_shared<reflection_field>(fieldName, fieldType, offset));
    }

    /**
     * @brief 获得类字段数量
     *
     * @param[in] className
     * @return std::size_t
     */
    std::size_t field_num(const std::string &className)
    {
        return m_fields[className].size();
    }

    /**
     * @brief 获得类字段
     *
     * @param[in] className
     * @param[in] index
     * @return std::shared_ptr<reflection_field>
     */
    std::shared_ptr<reflection_field> field(const std::string &className, std::size_t index)
    {
        std::size_t size = m_fields[className].size();
        if (index >= size)
            return nullptr;
        return m_fields[className][index];
    }

    /**
     * @brief 获得类字段
     *
     * @param[in] className
     * @param[in] fieldName
     * @return std::shared_ptr<reflection_field>
     */
    std::shared_ptr<reflection_field> field(const std::string &className, const std::string &fieldName)
    {
        for (auto field : m_fields[className])
        {
            if (field->name() == fieldName)
                return field;
        }
        return nullptr;
    }

    /**
     * @brief 注册类方法
     *
     * @param[in] className
     * @param[in] methodName
     * @param[in] method
     */
    void register_method(const std::string &className, const std::string &methodName, uintptr_t method)
    {
        m_methods[className].emplace_back(std::make_shared<reflection_method>(methodName, method));
    }

    /**
     * @brief 获得类方法数量
     *
     * @param[in] className
     * @return std::size_t
     */
    std::size_t method_num(const std::string &className)
    {
        return m_methods[className].size();
    }

    /**
     * @brief 获得类方法
     *
     * @param[in] className
     * @param[in] index
     * @return std::shared_ptr<reflection_method>
     */
    std::shared_ptr<reflection_method> method(const std::string &className, std::size_t index)
    {
        std::size_t size = m_methods[className].size();
        if (index >= size)
            return nullptr;
        return m_methods[className][index];
    }

    /**
     * @brief 获得类方法
     *
     * @param[in] className
     * @param[in] methodName
     * @return std::shared_ptr<reflection_method>
     */
    std::shared_ptr<reflection_method> method(const std::string &className, const std::string &methodName)
    {
        for (auto method : m_methods[className])
        {
            if (method->name() == methodName)
                return method;
        }
        return nullptr;
    }

  private:
    std::map<std::string, creator> m_creators;
    std::map<std::string, std::vector<std::shared_ptr<reflection_field>>> m_fields;
    std::map<std::string, std::vector<std::shared_ptr<reflection_method>>> m_methods;
};

} // namespace details

using reflection_factory = singleton<details::reflection_factory>;

class reflective
{
  public:
    reflective() = default;
    virtual ~reflective() = default;

    /**
     * @brief 获得类名
     *
     * @return const std::string&
     */
    const std::string &class_name() const noexcept
    {
        return m_className;
    }

    /**
     * @brief 设置类名
     *
     * @return std::string&
     */
    std::string &class_name() noexcept
    {
        return m_className;
    }

    /**
     * @brief 借助 reflection_factory 获得类信息
     *
     * @return std::size_t
     */
    std::size_t field_num() const noexcept
    {
        return reflection_factory::instance().field_num(m_className);
    }

    /**
     * @brief 获得类字段
     *
     * @param[in] index
     * @return std::shared_ptr<details::reflection_field>
     */
    std::shared_ptr<details::reflection_field> field(std::size_t index) const noexcept
    {
        return reflection_factory::instance().field(m_className, index);
    }

    /**
     * @brief 获得类字段
     *
     * @param[in] fieldName
     * @return std::shared_ptr<details::reflection_field>
     */
    std::shared_ptr<details::reflection_field> field(const std::string &fieldName) const noexcept
    {
        return reflection_factory::instance().field(m_className, fieldName);
    }

    /**
     * @brief 由于无法通过返回值类型匹配模板，只能通过参数传入 value
     *
     * @tparam T
     * @param[in] fieldName
     * @param[in] value
     */
    template <typename T> void value(const std::string &fieldName, T &value) const
    {
        auto field = reflection_factory::instance().field(m_className, fieldName);
        if (field == nullptr)
            return;
        value = *(T *)((std::size_t)this + field->offset());
    }

    /**
     * @brief 由于无法通过返回值类型匹配模板，只能通过参数传入 value
     *
     * @tparam T
     * @param[in] fieldName
     * @param[in] value
     */
    template <typename T> void set_value(const std::string &fieldName, const T &value)
    {
        auto field = reflection_factory::instance().field(m_className, fieldName);
        if (field == nullptr)
            return;
        *(T *)((std::size_t)this + field->offset()) = value;
    }

    /**
     * @brief 方法数
     *
     * @return std::size_t
     */
    std::size_t method_num() const noexcept
    {
        return reflection_factory::instance().method_num(m_className);
    }

    /**
     * @brief 获得类方法
     *
     * @param[in] index
     * @return std::shared_ptr<details::reflection_method>
     */
    std::shared_ptr<details::reflection_method> method(std::size_t index) const noexcept
    {
        return reflection_factory::instance().method(m_className, index);
    }

    /**
     * @brief 获得类方法
     *
     * @param[in] methodName
     * @return std::shared_ptr<details::reflection_method>
     */
    std::shared_ptr<details::reflection_method> method(const std::string &methodName) const noexcept
    {
        return reflection_factory::instance().method(m_className, methodName);
    }

    /**
     * @brief 使用变长参数模板调用类方法
     *
     * @tparam T
     * @tparam Args
     * @param[in] methodName
     * @param[in] args
     * @return T
     */
    template <typename T = void, typename... Args> T call(const std::string &methodName, Args... args)
    {
        auto method = reflection_factory::instance().method(m_className, methodName);
        if (method == nullptr)
            return T{};

        // 借助 decltype(this) 获得 this 指针的类型
        return (*((std::function<T(decltype(this), Args...)> *)method->method()))(this, std::forward<Args>(args)...);
    }

  private:
    std::string m_className;
};

namespace details
{

// 注册器，利用 RAII 机制，自动注册类，自动销毁。注册器调用工厂的注册字段函数，不需要友元关系
class reflection_register
{
  public:
    /**
     * @brief 注册构造函数
     *
     * @param[in] name
     * @param[in] creator
     */
    reflection_register(const std::string &name, creator creator)
    {
        singleton<reflection_factory>::instance().register_class(name, creator);
    }

    /**
     * @brief 注册类字段
     *
     * @param[in] className
     * @param[in] fieldName
     * @param[in] fieldType
     * @param[in] offset
     */
    reflection_register(const std::string &className, const std::string &fieldName, const std::string &fieldType,
                        std::size_t offset)
    {
        singleton<reflection_factory>::instance().register_field(className, fieldName, fieldType, offset);
    }

    /**
     * @brief 注册类方法
     *
     * @param[in] className
     * @param[in] methodName
     * @param[in] method
     */
    reflection_register(const std::string &className, const std::string &methodName, uintptr_t method)
    {
        singleton<reflection_factory>::instance().register_method(className, methodName, method);
    }
};

} // namespace details

} // namespace utils

} // namespace xy

// 注册类名
#define REGISTER_CLASS(className)                                                                                      \
    std::unique_ptr<xy::utils::reflective> _createObject##className()                                                  \
    {                                                                                                                  \
        auto p = std::make_unique<className>();                                                                        \
        p->class_name() = #className;                                                                                  \
        return p;                                                                                                      \
    }                                                                                                                  \
    xy::utils::details::reflection_register _register##className(#className, _createObject##className);

// 注册字段
#define REGISTER_FIELD(className, fieldName, fieldType)                                                                \
    className _className##fieldName;                                                                                   \
    xy::utils::details::reflection_register _register##className##fieldName(                                           \
        #className, #fieldName, #fieldType,                                                                            \
        (std::size_t)&_className##fieldName.fieldName - (std::size_t)&_className##fieldName);

// 注册方法，注意由于使用 /Zc:preprocessor 编译器选项，需要在方法定义前加上 __VA_OPT__ 宏，否则会导致参数展开错误
#define REGISTER_METHOD(className, methodName, returnType, ...)                                                        \
    std::function<returnType(className *__VA_OPT__(, ) __VA_ARGS__)> _register##className##methodName##Func =          \
        &className::methodName;                                                                                        \
    xy::utils::details::reflection_register _register##className##methodName(                                          \
        #className, #methodName, (uintptr_t)(&_register##className##methodName##Func));